package com.inibb.app.web.filter;


import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.web.filter.OncePerRequestFilter;

import com.inibb.app.exception.SessionTimeoutException;
import com.inibb.app.util.SecurityUtils;
import com.inibb.app.util.lang.StringUtil;




public class SessionTimeoutFilter extends OncePerRequestFilter {

	private final static Log LOG = LogFactory.getLog(SessionTimeoutFilter.class); 
	
	private String bypassURL;

	public String getBypassURL() {
		return bypassURL;
	}

	public void setBypassURL(String bypassURL) {
		this.bypassURL = bypassURL;
	}

	private String checkUserObject;
	
	private String sessionAttributeToCheck;
	
	private String timeoutURL = "/logout.do";
	
	public void setTimeoutURL(String timeoutURL){
		this.timeoutURL = timeoutURL;
	}

	public String getSessionAttributeToCheck() {
		return sessionAttributeToCheck;
	}

	public void setSessionAttributeToCheck(String sessionAttributeToCheck) {
		this.sessionAttributeToCheck = sessionAttributeToCheck;
	}

	public String getCheckUserObject() {
		return checkUserObject;
	}

	public void setCheckUserObject(String checkUserObject) {
		this.checkUserObject = checkUserObject;
	}

	@Override
	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		HttpServletRequest req = request;
		String[] bypassUrls = null;
		boolean isBypassUrl = false;
		HttpSession session = null;
		String url = StringUtil.toString(req.getRequestURL());
		request.setAttribute("url", url);

		if(bypassURL!=null){
			bypassUrls = StringUtil.tokenize(bypassURL, ",");
			for(String s:bypassUrls){
				if(url.indexOf(StringUtil.trim(s))!=-1){
					isBypassUrl = true;
					break;
				}
			}
			session = req.getSession();
		}
		String contextPath = req.getContextPath();
		if(!isBypassUrl){	
			LOG.debug("checking session status.");
			session = req.getSession(false);
			if(session==null){
				LOG.warn("session timeout detected...");
				//HttpServletResponse resp = (HttpServletResponse)response;
				//response.sendRedirect(contextPath+timeoutURL);
				throw new SessionTimeoutException("Session Timeout");
				//throw new SessionTimeoutException("http session timeout!!!");
			}else{
				if(!isSessionValid(request)){
					//response.sendRedirect(contextPath+timeoutURL);
					throw new SessionTimeoutException("Session Timeout");
					
					
				}else{
					if("TRUE".equalsIgnoreCase(checkUserObject)){
						LOG.debug("SecurityUtils.getUser()="+SecurityUtils.getUser());
						if(session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY)==null){
							LOG.debug("session timeout detected...");
							//HttpServletResponse resp = (HttpServletResponse)response;
							//response.sendRedirect(contextPath+timeoutURL);
							throw new SessionTimeoutException("Session Timeout");
							//throw new SessionTimeoutException("user object is null, session timeout!!!");
						}
		
					}
				}
			}
		}
		filterChain.doFilter(request, response);
	}
	
	private boolean isSessionValid(HttpServletRequest request){
		if(request.getSession(false)!=null){
			try{
				Object o = request.getSession(false).getAttribute(this.getSessionAttributeToCheck());
				if(!StringUtil.isEmptyString(this.getSessionAttributeToCheck())){
					if(o==null){
						LOG.warn("Since null object found in session attribute, current session is invalid!");
						return false;
					}
				}
				LOG.debug("Session is valid!");
			}catch(IllegalStateException e){
				LOG.warn("Session is invalidated!");
				return false;
			}
		}
		return true;
	}

}
